#pragma once
#include "requestor.hpp"

namespace rpc
{
    namespace client
    {
        class TopicManager
        {
        public:
            using SubCallback = std::function<void(const std::string &, const std::string &)>;
            using ptr = std::shared_ptr<TopicManager>;
            TopicManager(const Requestor::ptr &requestor)
                : _requestor(requestor)
            {}
            // 创建主题
            bool create(const BaseConnection::ptr &conn, const std::string &key)
            {
                return onCommonTopic(conn, key, TOPIC_OPTION::TOPIC_CREATE);
            }
            // 删除主题
            bool remove(const BaseConnection::ptr &conn, const std::string &key)
            {
                return onCommonTopic(conn, key, TOPIC_OPTION::TOPIC_REMOVE);
            }
            // 订阅主题:订阅主题后要设置函数来进行处理
            bool subscribe(const BaseConnection::ptr &conn, const std::string &key, const SubCallback &cb)
            {
                // 订阅主题时要将回调函数和key管理起来
                appendSubscribe(key, cb);
                bool ret = onCommonTopic(conn, key, TOPIC_OPTION::TOPIC_SUBSCRIBE);
                if (ret == false)
                {
                    // 如果创建失败了还要删除掉key和回调函数的关联关系
                    delSubscribe(key);
                    return false;
                }

                return true;
            }
            // 取消订阅
            bool cancel(const BaseConnection::ptr &conn, const std::string &key)
            {
                return onCommonTopic(conn, key, TOPIC_OPTION::TOPIC_CANCEL);
            }
            // 发布主题
            bool publish(const BaseConnection::ptr &conn, const std::string &key, const std::string &msg)
            {
                return onCommonTopic(conn, key, TOPIC_OPTION::TOPIC_PUBLISH, msg);
            }
            // 提供给dispacher模块的操作函数
            void onPublish(const BaseConnection::ptr &conn, const TopicRequest::ptr &msg)
            {
                // 先查看操作类型是否是publish
                auto type = msg->getTopicOption();
                if (type != TOPIC_OPTION::TOPIC_PUBLISH)
                {
                    errlog("收到了错误的请求类型");
                    return;
                }
                // 找到对应的函数进行处理
                auto callback = getSubCb(msg->getKeyTopic());
                if(!callback)
                {
                    errlog("该类型:%s没有找到对应的回调函数",msg->getKeyTopic().c_str());
                    return;
                }

                callback(msg->getKeyTopic(), msg->getTopicMessage());
            }

        private:
            bool onCommonTopic(const BaseConnection::ptr &conn, const std::string &key, const TOPIC_OPTION &optype, std::string msg = std::string())
            {
                // 构造请求并填充数据
                auto req = MessageFactory::create<TopicRequest>();
                req->setId(UUID::uuid());
                req->setMytype(MY_TYPE::REQ_TOPIC);
                req->setKeyTopic(key);
                req->setTopicOption(optype);
                if (optype == TOPIC_OPTION::TOPIC_PUBLISH)
                {
                    req->setTopicMessage(msg);
                }
                BaseMessage::ptr rsp;
                bool ret = _requestor->send(conn, req, rsp);
                if (ret == false)
                {
                    errlog("消息发送失败");
                    return false;
                }
                auto topic_rsp = std::dynamic_pointer_cast<TopicResponse>(rsp);
                if (!topic_rsp)
                {
                    errlog("消息类型转换失败");
                    return false;
                }

                if (topic_rsp->getRecode() != MY_CODE::RCODE_OK)
                {
                    errlog("消息响应码错误");
                    return false;
                }

                return true;
            }

            // 添加关联关系
            void appendSubscribe(const std::string &key, const SubCallback &cb)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _callbacks.insert(std::make_pair(key, cb));
            }
            // 删除关联关系
            void delSubscribe(const std::string &key)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _callbacks.erase(key);
            }

            // 找到对应的处理函数
            const SubCallback getSubCb(const std::string &key)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _callbacks.find(key);
                if (it == _callbacks.end())
                {
                    return SubCallback();
                }

                return it->second;
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, SubCallback> _callbacks;
            Requestor::ptr _requestor;
        };
    }
}